\space 20 \CENTER on TURBO PASCAL CODING CONVENTIONS (mine 12/24/93) \space 20 \CENTER off Howard Richoux 6721 Shamrock Rd. Lincoln, NE 68506-2821 (402) 488-5867 \new \footer1 '@date|Turbo Pascal Coding|Page @page' General \join 72 I have been programming for close to 25 years, on a variety of machines in a variety of languages. Programmer support tools seem to lag far behind the language, appearing only when the machine or language is about obsolete. I am particularly peeved with text editors. The needs have changed little over the years, but command names and syntaxes require constant retraining of fingers. I am not fanatic about coding standards, although, I find it very difficult to study code which doesn't conform to my own conventions. I am willing to be persuaded to adopt any or all standards IF: \join off 1. It doesn't require a lot of extra typing. 2. A utility is provided to convert non-conforming code to the standard. (Not just a pretty listing). \join on Pascal coding conventions can be divided into (at least) two groups. General program construction practices and formatting rules. The program construction practices include file naming, directory organization, code library/unit use and use of global variables. Formatting rules would cover comments, indentation, capitalization and the layout of procedures within a file. Many conventions are historical in nature, based on earlier limitations of hardware or compilers. Sometimes it is easier to maintain the standard than to recognize that it is no longer needed. A few things to consider are: \join off 1. TURBO Pascal has been around since the days of the 8088 and the 10 Mbyte disk. Between the improvements in the compiler and the hardware, compile speed has increased by at least a factor of 100. 2. The invention of the Unit is one of the great contributions to programming. They can be compiled separately and linked intelligently, allowing code to be placed in logical groupings with almost no penalties in compile time or program size. 3. Borland's implementation of Objects is another major step forward, but I have not adapted fully to the paradigm shift. I use them frequently, but probably not completely correctly. I view them more as extensions to the Unit concept rather than as a religious experience. 4. Code was meant to be shared. There are enough programming jobs left to be done that we shouldn't need to hoard our resources. All of the general work I am doing is placed in the PUBLIC DOMAIN. Feel free to borrow, modify, plagerize and utilize it. All I would request is a footnote in your documentation and/or the placing of some of your code into the public domain. \new Program Construction - General \join on Some of the programming conventions are forced on us by the limitations of the language/compiler. Variables and Procedures need to be declared before they are referenced. Some are imposed by the operating system. Fiel names can only be 8 chars with a 3 char extension, 'pas' means pascal source file, etc. In no particular order, here are some thoughts (Remember, I don't claim I follow all of them to the letter): \join off 1. Minimize the use of global variables. It is too easy to reference them or modify them in another part of the code. The penalty of stack use and hence execution time is normally minimal, and is dwarfed by improvements in hardware. If globals are needed, hide them in Units or objects where the scope is at least limited. 2. *CONTROVERSIAL* Minimize the use of COMMENTS in code. Contrary to conventional wisdom, I have found that commenting the obvious is of no help later on, and the sheer mass of characters obscures the code structure. I have found that a large block of comments near the beginning of a unit can document the use of variables without obstructing code later on. 3. Instead, Name your variables wisely. Properly chosen names can make the code read well and self-document. I tend to favor mixed capitals for variable names with the capitals at the start of words within the names such as "PrintFlag" and "DecodeString". 4. Indentation can drive a stranger crazy. I can't even read code that looks like: IF x = 3 then begin DO WHILE i < 22 begin z := 4; end; end else begin b := 1; end; Some people swear by it. ( I'm not sure I have the bad example right, but the main feature is a snakey, constantly changing indentation.) I use: IF x = 3 then begin DO WHILE i < 22 begin z := 4; end; end else begin b := 1; end; With a level change of 4 or 5 spaces, code on the same lexical level stands out, making it easier to spot unmatched begin/ends and other syntactical problems. The objection I've heard to 5 char indentation is that you run out of room on the right side of the line. My answer is that in most cases, if you have to indent 4 or 5 levels, the procedure should probably have been broken down into multiple procedures anyway. 5. I can live with most combinations of upper and lower case letters, as long as it is reasonably consistant. I have seen good use of capitalization of language elements, lower case variables and also the opposite. I came from the punch-card all capitals world, went to a religiously all lower-case shop and wound up muddled. Over-use of upper case is hard on the eyes without contributing much information. 6. One of the most useful and hardest conventions to do well is to name variables, functions and procedures in such a way as to have the name imply its origin and/or use. If all of your global boolean flag variables are named xxxxFlag then it is much easier to read " If PrintFlag then ...". I tend to make symmetric functions and procedures, even when I don't need the reverse operation at present, just so it will be there later. So, if I convert integer to string with IntegerString, I will code, or at least mentally reserve procedures for RealString, StringInteger for later. This also allows me to see if the syntax is obvious, or at least straight-forward. 7. The single hardest coding function is CHANGE. When libraries have been built up and 20 or 30 programs are using them, how can you rename a low level procedure? This is a problem with no easy solution. Some of it can be avoided by naming well early. Some can be avoided by hiding functions inside units and objects. Some can be fixed by good coding tools search and replace text processors and the like. The problem is magnified greatly with multiple sites. \new Program Construction - Detail The following is a list of recommended procedures. I will try to use them in my code. They may not be good for all people, but they work for me. \join off Variables. 1. Use as few global variables as possible. 2. Reserve one and two character names for temporary type variables A procedure should declare them locally. Global temporaries cause no end of trouble because the contents are uncertain. var s,s1,s2 ... : string; i,j,k : integer; { an old FORTRAN hold-over} b : byte; 3. Except for very specific uses, don't bother with specific length strings. Var ext : string; for holding file extensions is a waste of 250+ bytes of data space, but the alternatives of creating a type ext_string = string[3]; causes pains in parameter passing and declarations(what did I name that file extension type? "extstring"? "type_ext"? ...) Simply declaring variables string[3] is a real disaster when you want to change it to string[4]. It is worth noting that use of objects tends to move a lot of data space onto the heap which is much more plentiful. 4. Choose variable names such that the code which uses them can be read out loud. "DO PlaceStringOnHeap(s) until ...;" Reads better than "DO HeapString(s) until ..." 5. Conversely, use of 3 or 4 descriptive names in a single statement can be very hard to follow, even though technically correct. "If (IndexMaximum > NumberofDataItems) then IncreaseSizeofDataArea;" reads like a ton of bricks. "NdxMax", "DataCnt", and other frequently used shortcuts are no less readable, and save typing and spelling errors. The trick is to always use the same shortcut for the same word. 6. The world needs to agree on the meaning of a few terms, then use them appropriately. One man's "indent" is another woman's "offset" or "margin" or "leftmargin" or "pad" ... This winds up being critical for providing run-time options for utility programs. One way to solve this is to have the library provide "free" decoding for a host of standard options. It then becomes much easier to use the provided options rather than code your own support. 7. Write your code such that 50+% of it is re-useable. EVERY program should contribute at least one routine to your library. Primarily this breaks down to taking one step back when coding and separating the exact problem you are attempting to solve from the more general methods you are using to solve it. For example, if you need to decode a string which looks like "xxxxx(yyy)" into the x and y pieces, write the routine to pass the delimiter pair as arguments (or global variables, or compile time constants), and name the routine such that you know that the function is general. Spend an extra 10% of time adding error checking code and then the next program will have a "free" component. The cost of this (there is ALWAYS a cost) is most probably run-time efficiency. Generalized code will not be quite as tight as code which solves exactly the one specific problem. It has been 15-20 years since the cost of hardware was more important than programming/ debugging costs. Hardware seems to improve by a factor of 2 every year, programmers pick up maybe 10% per year from better tools and experience. My vote is - when given a choice between ease of coding and speed of running, take the coding and go back and optimize later. Chances are, you won't need to.